package com.cybertron.ironhide.spider.xml;

import org.eweb4j.util.xml.AttrTag;
import org.eweb4j.util.xml.Skip;

import com.cybertron.ironhide.spider.Counter;
import com.cybertron.ironhide.spider.SiteManager;
import com.cybertron.ironhide.spider.SpiderListener;
import com.cybertron.ironhide.spider.plugin.BeginPoint;
import com.cybertron.ironhide.spider.plugin.DigPoint;
import com.cybertron.ironhide.spider.plugin.DupRemovalPoint;
import com.cybertron.ironhide.spider.plugin.EndPoint;
import com.cybertron.ironhide.spider.plugin.ExtensionPoint;
import com.cybertron.ironhide.spider.plugin.ExtensionPoints;
import com.cybertron.ironhide.spider.plugin.FetchPoint;
import com.cybertron.ironhide.spider.plugin.ParsePoint;
import com.cybertron.ironhide.spider.plugin.PluginManager;
import com.cybertron.ironhide.spider.plugin.Point;
import com.cybertron.ironhide.spider.plugin.PojoPoint;
import com.cybertron.ironhide.spider.plugin.TargetPoint;
import com.cybertron.ironhide.spider.plugin.TaskPoint;
import com.cybertron.ironhide.spider.task.TaskDbServer;
import com.cybertron.ironhide.spider.task.TaskQueue;

public class Site {

	@AttrTag
	private String name;// 网站名

	@AttrTag
	private String host;// 主机名

	@AttrTag
	private String country;// 网站所属国家

	@AttrTag
	private String isDupRemovalStrict;// 是否严格去掉重复的TargetUrl，即已访问过一次的TargetUrl不会再被访问，若否，就算是重复的TargetUrl，只要它的来源URL不同，都会被访问

	@AttrTag
	private String isFollowRedirects;// 是否自动跟随重定向网页，默认是

	private ValidHosts validHosts;// 限制在这些host里面抓取数据

	private Options options;// 一些其他的业务数据

	@AttrTag
	private String url;// 网站url

	@AttrTag
	private String httpMethod;

	@AttrTag
	private String userAgent = "Spiderman[https://github.com/laiweiwei/spiderman]";// 爬虫一些标识

	@AttrTag
	private String includeHttps; // 是否抓取https页

	@AttrTag
	private String skipStatusCode;// 设置忽略哪些状态码，例如设置为500,那么针对这个网站的访问请求，就算返回500状态码，依然会去解析相应内容

	@AttrTag
	private String timeout;// HTTP请求最大等待时间

	@AttrTag
	private String reqDelay = "200";// 每个请求的延迟时间

	@AttrTag
	private String charset;// 网站内容字符集

	@AttrTag
	private String enable = "1";// 是否开启本网站的抓取

	@AttrTag
	private String thread = "1";// 线程数

	private Headers headers = new Headers();// HTTP头

	private Cookies cookies = new Cookies();// HTTP Cookie

	private Rules queueRules;// 允许进入抓取队列的url规则

	private Targets targets;// 抓取目标

	// ------------------------------------------
	@Skip
	public TaskDbServer db;// 每个网站都有属于自己的一个任务去重DB服务

	@Skip
	public Boolean isStop = false;// 每个网站都有属于自己的一个停止信号，用来标识该网站的状态是否停止完全

	@Skip
	public Counter counter;// 针对本网站已完成的任务数量

	@Skip
	public TaskQueue queue;

	// --------------扩展点-----------------------
	public TaskPoint taskPoint;

	public BeginPoint beginPoint;

	public FetchPoint fetchPoint;

	public DigPoint digPoint;

	public DupRemovalPoint dupRemovalPoint;

	public TargetPoint targetPoint;

	public ParsePoint parsePoint;

	public EndPoint endPoint;

	public PojoPoint pojoPoint;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getHost() {
		return host;
	}

	public void setHost(String host) {
		this.host = host;
	}

	public String getTimeout() {
		return this.timeout;
	}

	public void setTimeout(String timeout) {
		this.timeout = timeout;
	}

	public String getCountry() {
		return country;
	}

	public void setCountry(String country) {
		this.country = country;
	}

	public String getIsFollowRedirects() {
		return this.isFollowRedirects;
	}

	public void setIsFollowRedirects(String isFollowRedirects) {
		this.isFollowRedirects = isFollowRedirects;
	}

	public String getIsDupRemovalStrict() {
		return isDupRemovalStrict;
	}

	public void setIsDupRemovalStrict(String isDupRemovalStrict) {
		this.isDupRemovalStrict = isDupRemovalStrict;
	}

	public ValidHosts getValidHosts() {
		return this.validHosts;
	}

	public void setValidHosts(ValidHosts validHosts) {
		this.validHosts = validHosts;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getIncludeHttps() {
		return includeHttps;
	}

	public void setIncludeHttps(String includeHttps) {
		this.includeHttps = includeHttps;
	}

	public String getUserAgent() {
		return this.userAgent;
	}

	public void setUserAgent(String userAgent) {
		this.userAgent = userAgent;
	}

	public String getSkipStatusCode() {
		return this.skipStatusCode;
	}

	public void setSkipStatusCode(String skipStatusCode) {
		this.skipStatusCode = skipStatusCode;
	}

	public Options getOptions() {
		return this.options;
	}

	public void setOptions(Options options) {
		this.options = options;
	}

	public String getEnable() {
		return enable;
	}

	public void setEnable(String enable) {
		this.enable = enable;
	}

	public String getReqDelay() {
		return this.reqDelay;
	}

	public void setReqDelay(String reqDelay) {
		this.reqDelay = reqDelay;
	}

	public Targets getTargets() {
		return targets;
	}

	public void setTargets(Targets targets) {
		this.targets = targets;
	}

	public Rules getQueueRules() {
		return queueRules;
	}

	public void setQueueRules(Rules queueRules) {
		this.queueRules = queueRules;
	}

	public String getCharset() {
		return this.charset;
	}

	public void setCharset(String charset) {
		this.charset = charset;
	}

	public Headers getHeaders() {
		return this.headers;
	}

	public void setHeaders(Headers headers) {
		this.headers = headers;
	}

	public Cookies getCookies() {
		return this.cookies;
	}

	public void setCookies(Cookies cookies) {
		this.cookies = cookies;
	}

	public String getHttpMethod() {
		return this.httpMethod;
	}

	public void setHttpMethod(String httpMethod) {
		this.httpMethod = httpMethod;
	}

	public String getThread() {
		return thread;
	}

	public void setThread(String thread) {
		this.thread = thread;
	}

	public String getOption(String name) {
		if (options == null)
			return null;

		for (Option option : options.getOption()) {
			if (option == null || option.getName() == null
					|| option.getName().trim().length() == 0)
				continue;
			if (!option.getName().equals(name))
				continue;

			return option.getValue();
		}

		return null;
	}

	public void init(SiteManager siteManager, PluginManager pluginManager,
			SpiderListener listener) throws Exception {

		// 加载网站插件配置
		this.queue = siteManager.queue;
		for (String key : ExtensionPoints.toArray()) {
			ExtensionPoint<Point> extensionPoint = pluginManager
					.getExtensionPoint(key);
			if (extensionPoint == null) {
				continue;
			}
			Point point = extensionPoint.getExtension();
			point.init(this, listener);
			if (point instanceof TaskPoint) {
				taskPoint = (TaskPoint) point;
			}
			if (point instanceof BeginPoint) {
				beginPoint = (BeginPoint) point;
			}
			if (point instanceof EndPoint) {
				endPoint = (EndPoint) point;
			}
			if (point instanceof FetchPoint) {
				fetchPoint = (FetchPoint) point;
			}
			if (point instanceof DigPoint) {
				digPoint = (DigPoint) point;
			}
			if (point instanceof DupRemovalPoint) {
				dupRemovalPoint = (DupRemovalPoint) point;
			}
			if (point instanceof TargetPoint) {
				targetPoint = (TargetPoint) point;
			}
			if (point instanceof ParsePoint) {
				parsePoint = (ParsePoint) point;
			}
			if (point instanceof EndPoint) {
				endPoint = (EndPoint) point;
			}
			if (point instanceof PojoPoint) {
				pojoPoint = (PojoPoint) point;
			}
		}

	}

	private void destroyPoint(Point point, SpiderListener listener) {
		if (point == null)
			return;
		try {
			point.destroy();
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null, "Plugin.point->"
					+ point + " destroy failed.", e);
		} finally {
			point = null;
		}
	}

	public void destroy(SpiderListener listener, boolean isShutdownNow) {

		try {
			destroyPoint(taskPoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".TaskPollPlugin destroy failed.", e);
		}

		try {
			destroyPoint(this.beginPoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".BeginPlugin destroy failed.", e);
		}
		try {
			destroyPoint(this.fetchPoint, listener);

		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".FetchPlugin destroy failed.", e);
		}
		try {
			destroyPoint(this.digPoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".DigPlugin destroy failed.", e);
		}
		try {
			destroyPoint(this.dupRemovalPoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".DupRemovalPlugin destroy failed.", e);
		}

		try {
			destroyPoint(this.targetPoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".TargetPlugin destroy failed.", e);
		}

		try {
			destroyPoint(this.parsePoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".ParserPlugin destroy failed.", e);
		}
		try {
			destroyPoint(this.pojoPoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".PojoPlugin destroy failed.", e);
		}

		try {
			destroyPoint(this.endPoint, listener);
		} catch (Exception e) {
			listener.onError(Thread.currentThread(), null,
					".EndPlugin destroy failed.", e);
		}

	}

}
